#!/usr/bin/env node
const discord = require('discord.js')
const config = require('./config')
const db = require('./db')
const Log = require('./util/log')

class Game {
  // Starts the game. Should only run once per process!
  async boot() {
    // Create an instance of the logging tool
    this.log = new Log()
    
    // Load the config file
    await config.load()

    // Connect to the database (nedb or mongodb)
    await db.connect()

    // Create the bot pool
    this.clientPool = await Promise.all(config.get('discord_bot_tokens').map(async token => {
      const client = new discord.Client()

      try {
        await client.login(token)
      } catch (err) {
        this.log.warning('Bot login failure (is the token correct?)')
        return null
      }

      if (client.guilds.find(g => g.id === config.get('discord_server_id'))) {
        this.log.info(`Bot ${client.user.tag} logged in successfully`)

        return client
      } else {
        this.log.warning('Bot not connected to configured Discord server - add it using the following URL:')
        this.log.warning(`https://discordapp.com/oauth2/authorize?&client_id=${client.user.id}&scope=bot&permissions=${0x00000008}&response_type=code`)
        
        return null
      }
    }).filter(promise => promise !== null))

    if (this.clientPool.length === 0) {
      throw 'No bots connected, cannot start'
    }

    // Add all players to the database (if they don't exist already)
    // This could take a while on large servers
    await Promise.all(this.guild.members.filter(m => !m.user.bot).map(async member => {
      const player = await db.Player.findOne({_id: member.id})
      
      if (!player) {
        this.log.info(`Creating player data for new user ${member.user.tag}`)
        await db.Player.create({_id: member.id}).save()
      }
    }))

    // TODO: other things
  }

  get guild() {
    return this.clientPool[0].guilds.find(g => g.id === config.get('discord_server_id'))
  }
}

// Let's go!!
const game = new Game()

game.boot()
  .then(() => game.log.info('Game started'))
  .catch(err => {
    // :(

    game.log.critical('Unhandled error during boot:')
    game.log.critical(err) // Human-friendly, handled errors are just strings

    process.exit(1)
  })
